package org.csu.mybigpro.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.csu.mybigpro.domain.Exam;
import java.io.ByteArrayOutputStream;
import org.csu.mybigpro.persistence.ExamMapper;
import org.csu.mybigpro.service.AiService;
import org.csu.mybigpro.service.IExamService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Service
public class ExamServiceImpl extends ServiceImpl<ExamMapper, Exam> implements IExamService {

    @Autowired
    private AiService aiService;

    @Autowired
    private ExamMapper examMapper;

    private final ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 【新方法】实现将试卷导出为Word文档的逻辑
     */
    @Override
    public ByteArrayInputStream exportExamToWord(Exam exam) throws Exception {
        try (XWPFDocument document = new XWPFDocument(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            // 1. 设置试卷大标题
            XWPFParagraph titleParagraph = document.createParagraph();
            titleParagraph.setAlignment(ParagraphAlignment.CENTER);
            XWPFRun titleRun = titleParagraph.createRun();
            titleRun.setText(exam.getTitle());
            titleRun.setBold(true);
            titleRun.setFontSize(20);
            titleRun.addBreak();

            // 2. 遍历并添加问题
            List<Map<String, Object>> questions = exam.getQuestions();
            int questionNumber = 1;
            for (Map<String, Object> q : questions) {
                // 问题题干
                XWPFParagraph questionParagraph = document.createParagraph();
                XWPFRun questionRun = questionParagraph.createRun();
                String type = "multiple-choice".equals(q.get("type")) ? "选择题" : "判断题";
                questionRun.setText(questionNumber + ". (" + type + ") " + q.get("question"));
                questionRun.setBold(true);

                // 选项
                if (q.containsKey("options")) {
                    Object optionsObj = q.get("options");
                    if (optionsObj instanceof Map) {
                        Map<?, ?> options = (Map<?, ?>) optionsObj;
                        options.forEach((key, value) -> {
                            XWPFParagraph optionParagraph = document.createParagraph();
                            // 缩进
                            optionParagraph.setIndentationLeft(400);
                            XWPFRun optionRun = optionParagraph.createRun();
                            optionRun.setText(key + ". " + value);
                        });
                    }
                }
                questionNumber++;
            }

            // 3. 添加答案区域
            titleRun.addBreak();
            XWPFParagraph answerTitleParagraph = document.createParagraph();
            XWPFRun answerTitleRun = answerTitleParagraph.createRun();
            answerTitleRun.setText("参考答案");
            answerTitleRun.setBold(true);
            answerTitleRun.setFontSize(16);

            int answerNumber = 1;
            for (Map<String, Object> q : questions) {
                XWPFParagraph answerParagraph = document.createParagraph();
                XWPFRun answerRun = answerParagraph.createRun();
                answerRun.setText(answerNumber + ". " + q.get("answer"));
                answerNumber++;
            }


            document.write(out);
            return new ByteArrayInputStream(out.toByteArray());
        }
    }

    @Override
    public Exam generateExam(String description) throws Exception {
        // 1. Call AI to get the exam structure
        String rawJsonResponse = aiService.generateExamFromDescription(description);

        // 2. Extract the clean JSON content from the raw AI response
        String cleanJson = extractJsonContent(rawJsonResponse);

        // 3. Parse the clean JSON into Exam object
        JsonNode rootNode = objectMapper.readTree(cleanJson);
        String title = rootNode.path("title").asText("AI-Generated Exam");
        List<Map<String, Object>> questions = Collections.emptyList();
        if (rootNode.has("questions")) {
            questions = objectMapper.convertValue(rootNode.path("questions"), new TypeReference<>() {});
        }


        // 4. Create and save the exam entity
        Exam exam = new Exam();
        exam.setTitle(title);
        exam.setQuestions(questions);
        exam.setStatus("DRAFT"); // Initial status
        exam.setCreatedAt(LocalDateTime.now());
        examMapper.insert(exam);

        return exam;
    }

    @Override
    public Exam publishExam(Long examId, int durationInMinutes) {
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new IllegalArgumentException("Exam not found with ID: " + examId);
        }

        exam.setStatus("PUBLISHED");
        exam.setDurationInMinutes(durationInMinutes);
        exam.setStartTime(LocalDateTime.now());

        examMapper.updateById(exam);

        // Here you could schedule a task to automatically finish the exam
        // For example, using Spring's @Scheduled or a task executor.
        // scheduler.schedule(() -> finishExam(examId), exam.getStartTime().plusMinutes(durationInMinutes));

        return exam;
    }


    /**
     * 【已重构】更健壮的、两阶段的JSON提取方法。
     * 1. 优先解析外层Google AI的响应结构。
     * 2. 如果失败或结构不符，则对原始文本进行强力清理，提取JSON部分。
     * @param rawResponse 来自AI的原始响应字符串
     * @return 清理后的纯试卷JSON字符串
     */
    private String extractJsonContent(String rawResponse) {
        try {
            // 阶段一：尝试按标准的Google AI API响应格式解析
            JsonNode rootNode = objectMapper.readTree(rawResponse);
            JsonNode textNode = rootNode.path("candidates").path(0).path("content").path("parts").path(0).path("text");

            if (!textNode.isMissingNode() && textNode.isTextual()) {
                // 如果成功提取内层文本，就清理这段文本
                return cleanRawText(textNode.asText());
            } else {
                // 如果结构不符合预期，直接清理整个原始响应
                return cleanRawText(rawResponse);
            }
        } catch (Exception e) {
            // 阶段二：如果整个响应都不是一个有效的JSON（说明AI可能返回了纯文本），
            // 就把整个原始响应作为待清理的文本。
            return cleanRawText(rawResponse);
        }
    }

    /**
     * 【新增的辅助方法】强力清理包含JSON的原始文本。
     * 它能处理JSON前后多余的文字和markdown代码块标记。
     * @param text 可能包含JSON的脏文本
     * @return 提取出的纯JSON字符串
     */
    private String cleanRawText(String text) {
        String trimmedText = text.trim();

        // 寻找第一个 '{' 或 '['，这标志着JSON内容的开始
        int firstBrace = trimmedText.indexOf('{');
        int firstBracket = trimmedText.indexOf('[');

        // 确定JSON的起始位置
        int startIndex;
        if (firstBrace == -1 && firstBracket == -1) {
            // 如果连 '{' 和 '[' 都没有，说明响应内容完全错误
            return "{}"; // 返回一个空的JSON对象，避免后续代码空指针，同时让业务逻辑失败
        } else if (firstBrace != -1 && firstBracket != -1) {
            startIndex = Math.min(firstBrace, firstBracket);
        } else {
            startIndex = Math.max(firstBrace, firstBracket);
        }

        // 寻找最后一个 '}' 或 ']'，这标志着JSON内容的结束
        int lastBrace = trimmedText.lastIndexOf('}');
        int lastBracket = trimmedText.lastIndexOf(']');
        int endIndex = Math.max(lastBrace, lastBracket);

        // 如果找到了合法的起止位置，就提取中间的子字符串
        if (endIndex > startIndex) {
            return trimmedText.substring(startIndex, endIndex + 1);
        }

        // 如果找不到，同样返回空JSON对象
        return "{}";
    }

}
